home *** CD-ROM | disk | FTP | other *** search
- #import "IconDragView.h"
- #import "ShelfView.h"
- #import "Controller.h"
-
- #import <appkit/appkit.h>
- #import <mach/mach.h>
- #import <bsd/sys/file.h>
-
-
- int mouseMoved(NXPoint *o, int n, int mask);
-
- typedef enum { Unknown, SameDeviceOperation, WriteNotAllowed, CrossDeviceOperation } DragStatus;
-
-
- @implementation IconDragView : IconView
-
- - initFrame:(const NXRect *) newFrame
- image:anImage
- data:(const void *) someData
- andLength:(unsigned int) newLength
- useSize:(BOOL) sizeValid
- {
- const char *const types[1] = {NXFilenamePboardType};
-
- altImage = nil;
- selected = NO;
-
- [self registerForDraggedTypes:types count:1];
- [super initFrame:newFrame image:anImage data:someData andLength:newLength
- useSize:sizeValid];
-
- return self;
- }
-
-
- - free
- {
- [altImage free];
- return [super free];
- }
-
-
- - drawSelf:(const NXRect *) rects :(int) rectCount
- {
- id tempImage = image;
-
- image = altImage ? altImage : image;
- [super drawSelf:rects :rectCount];
- image = tempImage;
-
- return self;
- }
-
-
- - image
- {
- return image;
- }
-
-
- - getData:(void **) aPtr andLength:(unsigned int *) aLength
- {
- *aPtr = data;
- *aLength = length;
- return self;
- }
-
- - mouseDown:(NXEvent *) e
- {
- BOOL shift, control;
- NXPoint mousePoint, offset;
- unsigned int mask = NX_LMOUSEDRAGGEDMASK|NX_LMOUSEUPMASK;
- NXEvent saveEvent;
- BOOL newState;
-
- shift = (e->flags & NX_SHIFTMASK) ? YES : NO;
- control = (e->flags & NX_CONTROLMASK) ? YES : NO;
- mousePoint = e->location;
- saveEvent = *e;
-
- [window addToEventMask:mask];
-
- /*
- * Handle selection
- */
- if (shift && selected)
- newState = NO;
- else
- newState = YES;
-
- if (!shift && newState)
- [superview deselectAll:self];
-
- if (newState != selected) {
- selected = newState;
- [self display];
- }
-
- /*
- * Detect drag
- */
- if (mouseMoved(&mousePoint, 2, mask)) {
- NXPoint imagePoint;
-
- [self getImagePoint:&imagePoint andHilitePoint:NULL];
-
- offset.x = mousePoint.x - e->location.x;
- offset.y = mousePoint.y - e->location.y;
-
- [self setState:NO];
- [superview setDragView:self onEvent:&saveEvent withOffset:&offset
- atLocation:&imagePoint];
- return self;
- }
-
- /*
- * If no drag, try to get workspace to do something
- */
- if (selected) {
- BOOL delivered = NO;
- id workspace = [Application workspace];
- NXPoint imageLoc, upperRight;
- NXRect superRect;
- NXEvent newEvent;
-
- [self getImagePoint:&imageLoc andHilitePoint:NULL];
- [self convertPoint:&imageLoc toView:nil];
- [window convertBaseToScreen:&imageLoc];
- imageLoc.y++; /* grody! necessary to make images line up */
-
- [superview getFrame:&superRect];
- upperRight.x = superRect.origin.x + superRect.size.width - 32;
- upperRight.y = superRect.origin.y + superRect.size.height - 32;
-
- /*
- * Before animating the icon, check for double click. If we
- * see a second click come in, then open the file. Otherwise,
- * just select it in Workspace.
- */
- if (![NXApp peekNextEvent:NX_LMOUSEDOWNMASK into:&newEvent
- waitFor:0.2 threshold:NX_MODALRESPTHRESHOLD]) {
- [workspace slideImage:image from:&imageLoc to:&upperRight];
- delivered = [workspace selectFile:data inFileViewerRootedAt:""];
- }
- else {
- [workspace slideImage:image from:&imageLoc to:&upperRight];
- (void) [NXApp getNextEvent:NX_LMOUSEDOWNMASK];
- delivered = [workspace openFile:data];
- }
-
- if (!delivered)
- NXBeep();
-
- [self setState:NO];
- }
-
- return self;
- }
-
-
- - (BOOL) acceptsFirstMouse
- {
- return YES;
- }
-
-
- - (BOOL) acceptsFirstResponder
- {
- return NO;
- }
-
-
- #define OPEN_DIR_ICON_FILE ".opendir.tiff"
- #define DEFAULT_OPEN_DIR_FILE "/usr/lib/NextStep/Workspace.app/WM.app/openFolder.tiff"
- #define OPEN_HIGHLIGHT "OpenHighlight.tiff"
-
- - getOpenImageForDirectory:(const char *) dirname
- {
- struct stat st;
- char buf[MAXPATHLEN];
- id newImage = nil;
-
- /*
- * See if there's a .opendir.tiff
- */
- strncpy(buf, dirname, sizeof(buf));
- strncat(buf, "/", sizeof(buf));
- strncat(buf, OPEN_DIR_ICON_FILE, sizeof(buf));
- if (access(buf, R_OK) == 0) {
- newImage = [[NXImage allocFromZone:[self zone]] initFromFile:buf];
- if (newImage)
- return newImage;
- }
-
- /*
- * Before we use the default image, see if this thing is the
- * root of a mounted file system, and use the appropriate icon
- * if it is.
- */
- if (stat(dirname, &st) >= 0 && st.st_ino == 2) {
- NXSize size;
- [image getSize:&size];
- newImage = [[NXImage allocFromZone:[self zone]] initSize:&size];
- if ([newImage lockFocus]) {
- NXPoint zeroPoint = {0,0};
- id highlight = [NXImage allocFromZone:[self zone]];
- char buf[MAXPATHLEN];
- NXBundle *bundle;
-
- bundle = [NXBundle bundleForClass:[self class]];
- if ([bundle getPath:buf forResource:OPEN_HIGHLIGHT ofType:"tiff"]) {
- [highlight initFromFile:buf];
- [image composite:NX_COPY toPoint:&zeroPoint];
- [highlight composite:NX_SOVER toPoint:&zeroPoint];
- [newImage unlockFocus];
- return newImage;
- }
- }
- }
-
- if (access(DEFAULT_OPEN_DIR_FILE, R_OK) == 0)
- newImage = [[NXImage allocFromZone:[self zone]] initFromFile:DEFAULT_OPEN_DIR_FILE];
-
- if (newImage != nil)
- return newImage;
- else
- return image;
- }
-
-
- /*
- * Figure out the various parameters of the drag.
- */
- - (DragStatus) dragStatusForPath:(char *) dragPath
- {
- char *destinationPath;
- unsigned int junk;
- struct stat st;
-
- [self getData:(void **) &destinationPath andLength:&junk];
-
- /*
- * See if we should be a dragging destination. We need some way to
- * make this extendible. One way would be to associate a remote
- * object with the node, and ask it what it means to drag the
- * incoming object over the one on the screen...
- *
- * For now, interpret the data as a string. Stat it to see if it's
- * a directory, and if it is, say yes subject to access constraints.
- */
- if (stat(destinationPath, &st) < 0 || (st.st_mode & S_IFMT) != S_IFDIR)
- return WriteNotAllowed;
- if (access(destinationPath, W_OK|X_OK) < 0)
- return WriteNotAllowed;
-
- /*
- * Cool! We're a directory. Check the directory from which we're
- * dragging, and see it's the same as this one, or if it's contained
- * in this one.
- */
- if (stat(destinationPath, &st) < 0)
- return Unknown;
- else {
- dev_t destDev = st.st_dev;
- ino_t destIno = st.st_ino;
-
- if (lstat(dragPath, &st) >= 0 &&
- st.st_dev == destDev && destIno == st.st_ino)
- return WriteNotAllowed;
- }
-
- /*
- * Handle the case where the dragging destination and the dragging
- * source are on different file systems. In this case, we want to
- * copy by default, not move.
- */
- if (stat(destinationPath, &st) >= 0) {
- dev_t destinationDevice = st.st_dev;
- if (lstat(dragPath, &st) >= 0)
- if (st.st_dev != destinationDevice)
- return CrossDeviceOperation;
- else
- return SameDeviceOperation;
- }
-
- return Unknown;
- }
-
-
- /*
- * Figure out what the drag operation should be for dragging a view onto
- * another view.
- */
- - (NXDragOperation) dragOperationForContext:(id <NXDraggingInfo>) dragInfo
- {
- NXDragOperation op = NX_DragOperationNone;
- NXDragOperation maskOp = [dragInfo draggingSourceOperationMask];
- id pb = [Pasteboard newName:NXDragPboard];
- char *dragPath, *nextPath;
- unsigned int junk;
- BOOL first = YES;
-
- [pb readType:NXFilenamePboardType data:&dragPath length:&junk];
-
- /*
- * We might have been asked to drag multiple files. Loop over all of
- * them to see if they all have the same drag op. Fail if they don't!
- */
- nextPath = dragPath;
- do {
- char path[MAXPATHLEN];
- NXDragOperation thisOp = maskOp;
-
- strncpy(path, nextPath, MAXPATHLEN);
- if (index(path, '\t'))
- *index(path, '\t') = '\0';
-
- switch ([self dragStatusForPath:path]) {
- case WriteNotAllowed:
- case Unknown:
- thisOp = NX_DragOperationNone;
- break;
- case CrossDeviceOperation:
- if (maskOp & NX_DragOperationCopy) {
- thisOp = NX_DragOperationCopy;
- break;
- }
- /* fall through */
- case SameDeviceOperation:
- if (maskOp & NX_DragOperationGeneric) {
- thisOp = NX_DragOperationGeneric;
- break;
- }
- /* fall through */
- default:
- break;
- }
-
- /*
- * Bail out of this operation isn't the same as the last one!
- */
- if (first) {
- op = thisOp;
- first = NO;
- }
- else
- if (op != thisOp)
- return NX_DragOperationNone;
-
- /*
- * Advance to next file
- */
- nextPath = index(nextPath, '\t');
- if (nextPath == NULL)
- break;
- else
- nextPath++;
-
- } while (1);
-
- return op;
- }
-
-
- /*
- * Be a dragging destination...
- */
- - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
- {
- lastDragOp = [self dragOperationForContext:sender];
-
- /*
- * If we're going to do the drag, use the alternate image.
- */
- if (lastDragOp != NX_DragOperationNone) {
- NXSize imageSize;
- altImage = [self getOpenImageForDirectory:data];
-
- [image getSize:&imageSize];
- [altImage setScalable:YES];
- [altImage setSize:&imageSize];
-
- [self display];
- }
-
- return lastDragOp;
- }
-
-
- - (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
- {
- lastDragOp = [self dragOperationForContext:sender];
- return lastDragOp;
- }
-
-
- - draggingExited:(id <NXDraggingInfo>)sender
- {
- /*
- * Reset image to original image.
- */
- [altImage free];
- altImage = nil;
- [self display];
- [window flushWindow];
- return self;
- }
-
-
- /*
- * Eat the result...
- */
- - (BOOL) prepareForDragOperation:sender
- {
- return YES;
- }
-
- - (BOOL) performDragOperation:(id <NXDraggingInfo>)sender
- {
- return YES;
- }
-
-
- - concludeDragOperation:(id <NXDraggingInfo>)sender
- {
- id workspace = [Application workspace];
- id pb = [Pasteboard newName:NXDragPboard];
- const char *wsmOp;
- char *pbData;
- unsigned int pbLength;
-
- switch (lastDragOp) {
- case NX_DragOperationGeneric:
- wsmOp = WSM_MOVE_OPERATION;
- break;
- case NX_DragOperationLink:
- wsmOp = WSM_LINK_OPERATION;
- break;
- case NX_DragOperationCopy:
- wsmOp = WSM_COPY_OPERATION;
- break;
- default:
- return NO;
- }
-
- [pb readType:NXFilenamePboardType data:&pbData length:&pbLength];
- [workspace performFileOperation:wsmOp source:"/" destination:data
- files:pbData options:NULL];
-
- return [self draggingExited:sender];
- }
-
-
- - (BOOL) isOnRemovableMedia
- {
- struct stat st;
- char *mountedList = NULL;
- id workspace = [Application workspace];
-
- if (stat(data, &st) < 0)
- device = 0;
- else
- device = st.st_dev;
-
- removable = NO;
- if ([workspace respondsTo:@selector(getMountedRemovableMedia:)] &&
- [workspace getMountedRemovableMedia:&mountedList])
- [self perform:@selector(isOnRemovableDevice:) withPaths:mountedList];
-
- if (mountedList)
- free(mountedList);
-
- return removable;
- }
-
-
- - isOnRemovableDevice:(const char *)path
- {
- struct stat st;
-
- if (path && stat(path, &st) >= 0)
- removable |= (device == st.st_dev);
-
- return self;
- }
-
-
- @end
-
-
- /*
- * Returns true if mouse is dragged more than n pixels from 'o',
- * false if the mouse button is lifted. If the mouse button is
- * lifted, the mouseUp event is not consumed.
- */
- int
- mouseMoved(NXPoint *o, int n, int mask)
- {
- NXEvent e;
- NXPoint p;
- float dx, dy;
-
- do {
- [NXApp peekNextEvent:mask into:&e waitFor:0x7fffffff
- threshold:NX_MODALRESPTHRESHOLD];
- p = e.location;
- if (e.type == NX_LMOUSEUP)
- break;
-
- (void) [NXApp getNextEvent:mask]; /* throw it away */
- dx = abs(p.x - o->x);
- dy = abs(p.y - o->y);
-
- } while ((dy < (float) n) && (dx < (float) n));
- *o = p;
-
- return e.type != NX_LMOUSEUP;
- }
-